# -*- coding: utf-8 -*-
from pcaspy import Driver, SimpleServer
from sys import exc_info
from src.SNMP_Proto import snmpset, snmpget
from os import environ
from re import sub
from src._logger import getLogger
from time import sleep, time
from os import getcwd, listdir
from json import loads
from multiprocessing.pool import ThreadPool as Pool
from src.imp_cmd import trigger
PATH = getcwd()
PORT = "5064"


class myDriver(Driver):
    def __init__(self, data_list, index_dict, host_dict, name_dict):
        Driver.__init__(self)
        self.logger = {}
        self.data_list = data_list
        self.host_dict = host_dict
        self.index_dict = index_dict
        self.name_dict = name_dict
        self.pool = Pool(processes=len(self.data_list))
        for data in set(self.name_dict.values()):
            self.logger[data] = getLogger(data)
        self.dbl = list(self.pvDB.keys())
        self.PRF = self.dbl[0]
        self.Ctrl = self.dbl[1]
        self.Trigger = self.dbl[2]
        # for i in self.dbl:
        #     print(i)
        self.pv_init()

    def pv_init(self):
        for data in self.data_list:
            return_data = snmpget(
                OIDname="impCtrlMENA", host=data["host"])
            # self.logger[data["name"]].debug(return_data)
            try:
                Enable_list = return_data.split("\n")[0:10]
                for key, value in data["data"].items():
                    msg = Enable_list[value].split("{}".format("INTEGER:"))
                    msg = sub("[^\d]".format("INTEGER:"), "", msg[1])
                    self.setParam(reason=key+"_Enable", value=int(msg))
                    # self.logger[data["name"]].debug(key+"_D:\t", float(msg)/250)

            except:
                self.logger[data["name"]].debug("Time System init Wrong !!!")

            return_data = snmpget(
                OIDname="impWavePatternTable1", host=data["host"])
            # self.logger[data["name"]].debug(return_data)
            try:
                Delay_list = return_data.split("\n")[0:10]
                Width_list = return_data.split("\n")[10:20]
                for key, value in data["data"].items():
                    msg = Delay_list[value].split("{}".format("Gauge32:"))
                    msg = sub("[^\d]".format("Gauge32:"), "", msg[1])
                    self.setParam(reason=key+"_D", value=(float(msg)/250))
                    # self.logger[data["name"]].debug(key+"_D:\t", float(msg)/250)
                    msg = Width_list[value].split("{}".format("Gauge32:"))
                    msg = sub("[^\d]".format("Gauge32:"), "", msg[1])
                    self.setParam(reason=key+"_W", value=(float(msg)/250))
                    # self.logger[data["name"]].debug(key+"_W:\t", float(msg)/250)

            except:
                self.logger[data["name"]].debug("Time System init Wrong !!!")

    def __del__(self):
        del self.logger

    def save_data(self):
        for data in self.data_list:
            return_data = snmpset(host=data["host"],
                                  OIDname="impCtrlApply.0", mask="INTEGER:", set_type="i", set_value=3)
            self.logger[data["name"]].info("impCtrlApply.0: ", return_data)

    def write(self, reason, value):
        if reason == self.Trigger:
            if value == 0:
                trigger("CLOSE")
            if value == 1:
                trigger("AC")
            if value == 2:
                trigger("VME")
            self.setParam(reason=reason, value=value)
            return True
        if value == self.getParam(reason=reason):
            return True
        self.pv_init()
        status = False
        self._E_Flag = False
        # take proper actions
        if reason == self.Ctrl:
            self.save_data()

        if reason == self.PRF:
            if value == 0:
                print("FREQ can't set 0")
                return status
            else:
                self.setParam(reason, value)
                status = self.runShell(opr_type="frequency")
        else:
            if reason[-7:] == "_Enable":
                self._E_Flag = True
                self.setParam(reason, value)
                status = self.runShell(pvname=reason[:-7])

            elif reason[-2:] == "_W":
                self.setParam(reason, value)
                status = self.runShell(pvname=reason[:-2])
                # 当AC模式时，重新触发，这两句哪里需要哪里搬
                # if self.getParam(self.Trigger) == 1:
                #     trigger("AC")
            elif reason[-2:] == "_D":
                self.setParam(reason, value)
                status = self.runShell(pvname=reason[:-2])
                # 当AC模式时，重新触发，这两句哪里需要哪里搬
                # if self.getParam(self.Trigger) == 1:
                #     #sleep(0.5)
                #     trigger("AC")
                #     sleep(1)
                #     trigger("AC")
                    


        return status

    def snmp_opr(self, pvname):
        # 获取数据
        FREQ = self.getParam(self.PRF)
        Width_us = self.getParam(pvname+"_W")
        Delay_us = self.getParam(pvname+"_D")
        Enable = self.getParam(pvname+"_Enable")
        self.logger[self.name_dict[pvname]].info("FREQ:{} Hz\tEnable:{}\tWidth:{} us\tDelay:{} us".format(
            FREQ, Enable, Width_us, Delay_us))
        # 计算数据
        T_ns = (1/FREQ)*10**9
        Width_ns = Width_us*10**3
        Delay_ns=Delay_us*10**3
        T_idle=Width_ns + Delay_ns
        if T_idle < T_ns:
            _100ms_num = int(
                (T_ns-T_idle)/(100*10**6))
            _4ns_num = int((T_ns-T_idle-_100ms_num*100*10**6)/4)
            self.logger[self.name_dict[pvname]].info("100ms:{}\t\t4ns:{}".format(
                _100ms_num, _4ns_num))
        else:
            _100ms_num = 0
            _4ns_num = 0

        # return_data = snmpset(host = self.data["host"],
        # OIDname="WavePatternIndexMC", mask="Gauge32:", set_type="u", set_value=0)
        # self.logger.info("WavePatternIndexMC: ", return_data)

        # 机箱下发
        if self._E_Flag:
            return_data = snmpset(host=self.host_dict[pvname],
                                  OIDname="impCtrlMC{}Ena".format(self.index_dict[pvname]), mask="INTEGER:", set_type="i", set_value=Enable)
            self.logger[self.name_dict[pvname]].debug(
                "impCtrlMC{}Ena: ".format(self.index_dict[pvname]), return_data)
            return_data = snmpset(OIDname="impCtrlApply.0", host=self.host_dict[pvname],
                                  mask="INTEGER:", set_type="i", set_value=11)
            self.logger[self.name_dict[pvname]].debug(
                "impCtrlApply.0 ", return_data)
        else:
            return_data = snmpset(host=self.host_dict[pvname],
                                  OIDname="impWavePatternMC.0", mask="INTEGER:", set_type="i", set_value=self.index_dict[pvname])
            self.logger[self.name_dict[pvname]].debug(
                "impWavePatternMC: ", return_data)
            return_data = snmpset(OIDname="impWavePatternDelay.0", host=self.host_dict[pvname],
                                  mask="Gauge32:", set_type="u", set_value=int(Delay_us*250))
            self.logger[self.name_dict[pvname]].debug(
                "Delay us:", return_data)

            return_data = snmpset(OIDname="impWavePatternWidth.0", host=self.host_dict[pvname],
                                  mask="Gauge32:", set_type="u", set_value=int(Width_us*250))
            self.logger[self.name_dict[pvname]].debug(
                "Width us:", return_data)

            return_data = snmpset(OIDname="impWavePatternIdle4ns.0", host=self.host_dict[pvname],
                                  mask="Gauge32:", set_type="u", set_value=int(_4ns_num))
            self.logger[self.name_dict[pvname]].debug("4nm:", return_data)

            return_data = snmpset(OIDname="impWavePatternIdle100ms.0", host=self.host_dict[pvname],
                                  mask="Gauge32:", set_type="u", set_value=int(_100ms_num))
            self.logger[self.name_dict[pvname]].debug(
                "100ms:", return_data)

            return_data = snmpset(OIDname="impWavePatternSet.0", host=self.host_dict[pvname],
                                  mask="INTEGER:", set_type="i", set_value=1)
            self.logger[self.name_dict[pvname]].debug(
                "impWavePatternSet.0 ", return_data)

    def FRQ_Set(self, data):
        for pv in data["data"].keys():
            self.runShell(pvname=pv)

    def runShell(self, opr_type=None, pvname=None):
        self.updatePVs()
        try:
            if opr_type == "frequency":
                start_time = time()
                for data in self.data_list:
                    ret = self.pool.apply_async(
                        self.FRQ_Set, args=(data,))
                end_time = time()
                run_time = end_time-start_time
                print("耗时:%.2f" % float(run_time))
            else:
                self.logger[self.name_dict[pvname]].debug(
                    "Debug: Run : ", pvname, " index : ", self.index_dict[pvname])
                self.snmp_opr(pvname=pvname)
                self.logger[self.name_dict[pvname]].debug("Debug: Finish \n")
        except OSError:
            self.logger[self.name_dict[pvname]].error(
                'ERROR', str(exc_info()[1]))
            return False
        for reason in self.dbl:
            self.callbackPV(reason)
            self.callbackPV(reason)
        self.updatePVs()
        return True


def myServer(data_list):
    host_dict = {}
    index_dict = {}
    name_dict = {}
    environ["EPICS_CAS_SERVER_PORT"] = PORT
    prefix = ''
    # 频率
    pvdb1 = {
        'TIMS:WR:Frq_Set': {
            'type': 'float',
            'value': 1,
            'desc': "Frequency set",
            'unit': "Hz"
        },
        'TIMS:WR:Ctrl_Set': {
            'type': 'int',
            'value': 1,
            'desc': "Apply set"
        },
        'TIMS:WR:Trigger_Set': {
            'type': 'enum',
            'enums': ['close', 'ac', 'vme'],
            'value': 0
        }
    }
    pvdb2 = {}
    pvdb3 = {}
    pvdb4 = {}
    for i in data_list:
        for key, value in i["data"].items():
            # 脉宽
            pvdb2['{}_W'.format(key)] = {
                'type': 'int',
                'value': 0,
                'asyn': True,
                'unit': "us"
            }
            # 延时
            pvdb3['{}_D'.format(key)] = {
                'type': 'int',
                'value': 0,
                'asyn': True,
                'unit': "us"
            }
            # 使能
            pvdb4['{}_Enable'.format(key)] = {
                'type': 'int',
                'value': 0,
                'asyn': True
            }
            host_dict['{}'.format(key)] = i["host"]
            index_dict['{}'.format(key)] = value
            name_dict['{}'.format(key)] = i["name"]

    server = SimpleServer()
    server.createPV(prefix, pvdb1)
    server.createPV(prefix, pvdb2)
    server.createPV(prefix, pvdb3)
    server.createPV(prefix, pvdb4)
    server.setDebugLevel(level=0)
    driver = myDriver(data_list=data_list, index_dict=index_dict,
                      host_dict=host_dict, name_dict=name_dict)

    while True:
        server.process(0.1)


def main():
    config_file_list = [i.split(".")[0]
                        for i in listdir(PATH+"/config/")]
    data_list = []
    for file_name in config_file_list:
        with open(PATH+"/config/"+file_name+".json", "r", encoding="utf8") as fp:
            data = loads(fp.read())
            data_list.append(data)
            fp.close()
    myServer(data_list)

